home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Server Event Handler
- ** The server event handler usnit found in the AppleShare 3.0 Developer's
- ** Kit Server Control and Server Event Handling document.
- **
- ** by J. Luther, Apple Developer Technical Support
- ** Copyright Apple Computer, Inc. 1992-1994
- ** All rights reserved
- **
- ** Port from Pascal to C - 9/8/1994 JML
- **
- ** This file contains the server event handler, the server event record
- ** processor, and related routines.
- */
-
- /*****************************************************************************/
-
- #include <AppleTalk.h>
- #include <Processes.h>
- #include <Errors.h>
- #include <Memory.h>
- #include <Packages.h>
- #include "ServerControlIntf.h"
- #include "ServerEventIntf.h"
-
- /*****************************************************************************/
-
- /*
- ** This value indicates how many server events can be queued for
- ** ProcessServerEvents to handle later. If you expect a large number of
- ** server events to come in over a shart amount of time, increase this
- ** number.
- */
-
- enum
- {
- kNumberServerEvents = 100
- };
-
- /*****************************************************************************/
-
- /*
- ** Add required queue element fields to a server event record so we can
- ** use it as an OS queue element.
- */
-
- struct SERecQElem
- {
- QElemPtr qLink;
- short qType;
- ServerEventRecord theSERec;
- };
- typedef struct SERecQElem SERecQElem;
- typedef SERecQElem *SERecQElemPtr;
-
- /*
- ** Extend the tSEQEntry with a few items we need access to within the
- ** server event handler.
- */
-
- struct ExtendedSEQEntry
- {
- tSEQEntry theSEQEntry; /* a server event queue entry */
- QHdr freeQ, usedQ; /* queue headers for server */
- /* event record queues */
- SERecQElemPtr seRecArrayPtr; /* pointer to allocated array */
- /* of SERecQElem */
- ProcessSerialNumber ourPSN; /* the application's PSN */
- };
- typedef struct ExtendedSEQEntry ExtendedSEQEntry;
- typedef ExtendedSEQEntry *ExtendedSEQEntryPtr;
-
- /*****************************************************************************/
-
- /*
- ** The global extended tSEQEntry record
- */
-
- ExtendedSEQEntry gExtendedSEQEntry;
-
- /*****************************************************************************/
-
- OSErr InstallServerEventHandler(void);
-
- OSErr RemoveServerEventHandler(void);
-
- void ProcessServerEvents(void);
-
- /*****************************************************************************/
-
- /*
- ** This function calls SCInstallServerEventProc to install
- ** a server event handler.
- */
-
- static OSErr MySCInstallServerEventProc(const tSEQEntry * const theSEHandler)
- {
- SCParamBlockRec scPB;
-
- scPB.serverEventPB.scSEQEntryPtr = (Ptr)theSEHandler;
- scPB.serverEventPB.scCode = SCInstallServerEventProc;
-
- return ( SyncServerDispatch(&scPB) );
- }
-
- /*****************************************************************************/
-
- /*
- ** This function calls SCRemoveServerEventProc to remove a
- ** server event handler.
- */
-
- static OSErr MySCRemoveServerEventProc(const tSEQEntry * const theSEHandler)
- {
- SCParamBlockRec scPB;
-
- scPB.serverEventPB.scSEQEntryPtr = (Ptr)theSEHandler;
- scPB.serverEventPB.scCode = SCRemoveServerEventProc;
-
- return ( SyncServerDispatch(&scPB) );
- }
-
- /*****************************************************************************/
-
- /*
- ** TheSrvrEventHandler shows what should be done in a server event handler
- ** and no more: It gets a server event record from the free queue of
- ** application supplied server event records; it copies
- ** AppleShare's server event record (pointed to by theSERecPtr) into the
- ** application's server event record; it puts the application's server
- ** event record into the used queue where it can be serviced from the
- ** application's event loop; and then, it calls WakeUpProcess so the event
- ** loop can handle the server event record in the queue as soon as possible.
- **
- ** Note: This code handles the out of free server event record condition
- ** by getting the oldest server event record from the usedQ. Depending on
- ** your purposes for recording server events, you may want to do something
- ** different. For example, you may just want to set a flag to tell the
- ** ProcessServerEvents function to allocate more server event records (since
- ** you can't do that here).
- */
-
- static pascal void TheSrvrEventHandler(ExtendedSEQEntry * const theSEQPtr,
- const ServerEventRecord * const theSERecPtr)
- {
- SERecQElemPtr theSERecQElemPtr;
-
- if ( theSEQPtr->freeQ.qHead != NULL )
- {
- /* Get the server event record out of the freeQ */
- theSERecQElemPtr = (SERecQElemPtr)theSEQPtr->freeQ.qHead;
- /* Do nothing with errors. You'd better not be getting them! */
- (void) Dequeue((QElemPtr)theSERecQElemPtr, &(theSEQPtr->freeQ));
- }
- else
- {
- /* The freeQ is empty, so get the oldest server */
- /* event record out of the usedQ */
- theSERecQElemPtr = (SERecQElemPtr)theSEQPtr->usedQ.qHead;
- /* Do nothing with errors. You'd better not be getting them! */
- (void) Dequeue((QElemPtr)theSERecQElemPtr, &(theSEQPtr->usedQ));
- }
-
- /* Copy the server event record into my server event record */
- theSERecQElemPtr->theSERec = *theSERecPtr;
-
- /* And enqueue my server event record into the usedQ */
- Enqueue((QElemPtr)theSERecQElemPtr, &(theSEQPtr->usedQ));
-
- /* Wake up our process so it can handle the server event record ASAP */
- /* Do nothing with errors. You'd better not be getting them! */
- (void) WakeUpProcess(&(theSEQPtr->ourPSN));
- }
-
- /*****************************************************************************/
-
- /*
- ** InitSEQEntry initializes the fields of gExtendedSEQEntry to zero,
- ** allocates kNumberServerEvents of SERecQElem and enqueues them into the
- ** free queue of gExtendedSEQEntry, and gets the applications process
- ** serial number and puts it in gExtendedSEQEntry so the server event
- ** handler can wake up the process. InitSEQEntry returns true if the array
- ** of SERecQElem was allocated.
- */
-
- static Boolean InitSEQEntry(void)
- {
- SERecQElemPtr theQElemsPtr;
- short index;
- Boolean result = false;
-
- /* Point to server event handler */
- gExtendedSEQEntry.theSEQEntry.SEQentry.CallAddr =
- (ATalkTransitionEventUPP)TheSrvrEventHandler;
-
- /* Initially clear all SEeventFlags */
- gExtendedSEQEntry.theSEQEntry.SEeventFlag = 0;
-
- /* and clear all SEwhichAFPFlags */
- gExtendedSEQEntry.theSEQEntry.SEwhichAFPFlag[0] = 0;
- gExtendedSEQEntry.theSEQEntry.SEwhichAFPFlag[1] = 0;
-
- /* And clear all SEwhichSCFlags */
- gExtendedSEQEntry.theSEQEntry.SEwhichSCFlag = 0;
-
- /* Allocate some memory for the server event */
- /* records and initialize the buffer queues. */
- gExtendedSEQEntry.seRecArrayPtr =
- (SERecQElemPtr)NewPtr(kNumberServerEvents * (long)sizeof(SERecQElem));
- if ( gExtendedSEQEntry.seRecArrayPtr != NULL )
- {
- /* Initialize the usedQ header */
- gExtendedSEQEntry.usedQ.qFlags = 0;
- gExtendedSEQEntry.usedQ.qHead = NULL;
- gExtendedSEQEntry.usedQ.qTail = NULL;
-
- /* Initialize the freeQ header */
- gExtendedSEQEntry.freeQ.qFlags = 0;
- gExtendedSEQEntry.freeQ.qHead = NULL;
- gExtendedSEQEntry.freeQ.qTail = NULL;
-
- /* The free queue holds all of our server */
- /* event records initially, so add the */
- /* SERecQElems to the freeQ */
- theQElemsPtr = gExtendedSEQEntry.seRecArrayPtr;
- for ( index = 1; index <= kNumberServerEvents; ++index )
- {
- Enqueue((QElemPtr)theQElemsPtr, &(gExtendedSEQEntry.freeQ));
- ++theQElemsPtr;
- }
-
- result = true; /* everything is OK */
- }
-
- /* Get our process serial number */
- (void) GetCurrentProcess(&(gExtendedSEQEntry.ourPSN));
-
- return ( result );
- }
-
- /*****************************************************************************/
-
- /*
- ** SetSEFlags sets the server event flags of gExtendedSEQEntry to tell
- ** AppleShare's server event mechanism which server events your
- ** application's server event handler are interested in. You can set the
- ** SE flags either before or after your server event handler is installed.
- ** IMPORTANT NOTES:
- ** • Your server event handler will be called based on the current
- ** settings of SEeventFlag. Make sure SEeventFlag is either initialized
- ** to zero (meaning your server event handler is not interested in any
- ** server events) or initialized for the specific server events your
- ** application is interested in before you install your server event
- ** handler. }
- ** • If you set the bCSEHAFPInDoRequest or bCSEHAFPInSendResponse bits
- ** in SEeventFlag after your server event handler is installed, make
- ** sure you initialize the SEwhichAFPFlag bits first.
- ** • If you set the bCSEHServerControlCall bit in SEeventFlag after your
- ** server event handler is installed, make sure you initialize the
- ** SEwhichSCFlag bits first.
- */
-
- static void SetSEFlags(void)
- {
- /*
- ** If the bCSEHAFPInDoRequest or bCSEHAFPInSendResponse bits in
- ** SEeventFlag are going to be set, then indicate what AFP calls
- ** you're interested in. For example:
- ** gExtendedSEQEntry.theSEQEntry.SEwhichAFPFlag[1] &= (1L << afpOpenFork);
- ** will cause a server event for the afpOpenFork AFP call.
- */
-
- /* • add your code here • */
-
- /*
- ** If the bCSEHServerControlCall bit in SEeventFlag is going to be set,
- ** then indicate what server control calls you're interested in.
- ** For example:
- ** gExtendedSEQEntry.theSEQEntry.SEwhichSCFlag &= (1L << SCSetSetupInfo);
- ** will cause a server event for the SCSetSetupInfo server control call.
- */
-
- /* • add your code here • */
-
- /*
- ** Indicate what server events you'd like to be notified of by setting
- ** bits in the SEeventFlag longword. For example:
- ** gExtendedSEQEntry.SEeventFlag &= (1L << bCSEHVolumePrep);
- ** will cause a server event every time the server prepares a volume
- ** for use with AppleShare.
- */
-
- /* • add your code here • */
- }
-
- /*****************************************************************************/
-
- /*
- ** ProcessServerEvents should be called every time through the event loop
- ** to see if there are any server event records to process. If there aren't
- ** any, then it exits immediately. If there are any, then it processes the
- ** server event records in the used queue until none are left.
- ** This kind of assumes that processing server events doesn't take very long.
- ** If processing them is a time consuming processing, you might want to
- ** limit how many you process each time this routine is called.
- */
-
- void ProcessServerEvents(void)
- {
- SERecQElemPtr theSERecQElemPtr;
-
- while ( gExtendedSEQEntry.usedQ.qHead != NULL )
- {
- /* Get the server event record out of the usedQ */
- theSERecQElemPtr = (SERecQElemPtr)gExtendedSEQEntry.usedQ.qHead;
- if ( Dequeue((QElemPtr)theSERecQElemPtr, &gExtendedSEQEntry.usedQ) == noErr )
- {
- /* Do something useful with the server event record: */
- /* theSERecQElemPtr->theSERec */
-
- /* • add your code here • */
-
- /* We're done with the server event record, so put it back */
- /* in the freeQ */
- Enqueue((QElemPtr)theSERecQElemPtr, &gExtendedSEQEntry.freeQ);
- }
- }
- }
-
- /*****************************************************************************/
-
- /*
- ** Your application calls InstallServerEventHandler to install the server
- ** event handler. Change the InitSEQEntry function where indicated to tell
- ** the server event handler mechanism what server events you're interested
- ** in to begin with.
- */
-
- OSErr InstallServerEventHandler(void)
- {
- OSErr result;
-
- /* Initialize queues and get server event record buffer */
- if ( InitSEQEntry() == true )
- {
- /* Set the server event flags in */
- /* gExtendedSEQEntry.theSEQEntry */
- SetSEFlags();
-
- /* Install the server event handler */
- result = MySCInstallServerEventProc(&gExtendedSEQEntry.theSEQEntry);
-
- if ( result != noErr ) /* SE handler not installed? */
- {
- /* Then get rid of memory */
- DisposPtr((Ptr)gExtendedSEQEntry.seRecArrayPtr);
- }
- }
- else
- {
- /* Return a memory error */
- result = memFullErr;
- }
-
- return ( result );
- }
-
- /*****************************************************************************/
-
- /*
- ** Your application calls RemoveServerEventHandler to remove the server
- ** event handler and dispose of the memory allocated by InitSEQEntry (which
- ** is called by InstallServerEventHandler).
- */
-
- OSErr RemoveServerEventHandler(void)
- {
- OSErr result;
-
- /* Remove the server event handler */
- result = MySCRemoveServerEventProc(&gExtendedSEQEntry.theSEQEntry);
-
- /* Get rid of memory used for the server event records */
- if ( gExtendedSEQEntry.seRecArrayPtr != NULL )
- {
- DisposPtr((Ptr)gExtendedSEQEntry.seRecArrayPtr);
- }
-
- return ( result );
- }
-
- /*****************************************************************************/
-